name: CI_CD
on:
  # push:
  #   branches: 
  #   - main
  #   - staging
  workflow_dispatch:

jobs:
  build_image:
    runs-on: ubuntu-latest

    env:
      DOCKER_HUB: ${{ secrets.DOCKER_HUB }}
      DOCKERFILE: ci/dockerfile
    
    steps:
      - name: Git checkout
        uses: actions/checkout@v3
        
      - name: Get git short sha
        id: git
        run: |
          echo "short_sha=$(git rev-parse --short $GITHUB_SHA)" >> "$GITHUB_OUTPUT"

      - name: Get latest version of package json
        id: version
        uses: martinbeentjes/npm-get-version-action@main

      - name: Git
        run: |
          echo Short sha: ${{ steps.git.outputs.short_sha }}
          echo Version is: ${{ steps.version.outputs.current-version }}

      - name: Environment
        run: |
          echo DOCKER_HUB is: ${{ env.DOCKER_HUB }}
          echo DOCKERFILE is: ${{ env.DOCKERFILE }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2

      - name: Set up Docker Buildx for Builder
        uses: docker/setup-buildx-action@v3
        id: builder

      - name: Set up Docker Buildx for Main
        uses: docker/setup-buildx-action@v3
        id: main

      - name: Builder name
        run: echo ${{ steps.builder.outputs.name }}

      - name: Main name
        run: echo ${{ steps.main.outputs.name }}

      - name: Login to DockerHub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build builder
        uses: docker/build-push-action@v4
        with:
          builder: ${{ steps.builder.outputs.name }}
          file: ${{ env.DOCKERFILE }}
          target: builder

      - name: Build main and push
        uses: docker/build-push-action@v4
        if: ${{ github.ref_name == 'main' }}
        with:
          builder: ${{ steps.main.outputs.name }}
          file: ${{ env.DOCKERFILE }}
          build-args: |
            NODE_ENV=production
          target: main
          tags: |
            ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.DOCKER_HUB }}:latest
            ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.DOCKER_HUB }}:main_v${{ steps.version.outputs.current-version }}
            ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.DOCKER_HUB }}:main_v${{ steps.version.outputs.current-version }}_sha-${{ steps.git.outputs.short_sha }}
          push: true

      - name: Build staging and push 
        uses: docker/build-push-action@v4
        if: ${{ github.ref_name == 'staging' }}
        with:
          builder: ${{ steps.main.outputs.name }}
          file: ${{ env.DOCKERFILE }}
          build-args: |
            NODE_ENV=staging
          target: main
          tags: |
            ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.DOCKER_HUB }}:staging_v${{ steps.version.outputs.current-version }}
            ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.DOCKER_HUB }}:staging_v${{ steps.version.outputs.current-version }}_sha-${{ steps.git.outputs.short_sha }}
          push: true

  deploy_production:
    needs: [ build_image ]
    runs-on: ubuntu-latest
    if: ${{ github.ref_name == 'main' }}
    environment: production

    env: 
      DOCKER_HUB: ${{ secrets.DOCKER_HUB }}
      APP_NAME: ${{ vars.APP_NAME_PRODUCTION }}
      APP_PORT: 3000
      APP_PORT_EXPOSE: ${{ secrets.APP_PORT_PRODUCTION }}
      APP_NETWORK: app-network

      SSH_HOST: ${{ secrets.SSH_HOST_PRODUCTION }}
      SSH_PORT: ${{ secrets.SSH_PORT_PRODUCTION }}
      SSH_USER: ${{ secrets.SSH_USER_PRODUCTION }}
      SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY_PRODUCTION}}

    steps:
      - name: Git checkout
        uses: actions/checkout@v3
        
      - name: Get short sha commit
        id: git
        run: |
          echo "$(git rev-parse --short "$GITHUB_SHA")" >> "$GITHUB_OUTPUT"
      
      - name: Get latest version
        id: version
        uses: martinbeentjes/npm-get-version-action@main

      - name: Git
        run: |
          echo Short sha: ${{ steps.git.outputs.short_sha }}
          echo Version is: ${{ steps.version.outputs.current-version }}

      - name: Environment
        run: |
          echo DOCKER_HUB is: ${{ env.DOCKER_HUB }}
          echo APP_NAME is: ${{ env.APP_NAME }}
          echo APP_PORT is: ${{ env.APP_PORT }}
          echo APP_PORT_EXPOSE is: ${{ env.APP_PORT_EXPOSE }}
          echo APP_NETWORK is: ${{ env.APP_NETWORK }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Deploy
        uses: fifsky/ssh-action@master
        with:
          command: |
            docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.DOCKER_HUB }}:main_v${{ steps.version.outputs.current-version }}_sha-${{ steps.git.outputs.short_sha }}
            docker stop ${{ env.APP_NAME }} && docker rm ${{ env.APP_NAME }}
            docker network create ${{ env.APP_NETWORK }} --driver=bridge
            docker run -itd \
              --env NODE_ENV=production \
              --hostname ${{ env.APP_NAME }} \
              --publish ${{ secrets.APP_PORT_EXPOSE }}:${{ env.APP_PORT }} \
              --network ${{ env.APP_NETWORK }} \
              --volume /app/${{ env.APP_NAME }}/logs/:/app/logs/ \
              --volume /app/${{ env.APP_NAME }}/.env:/app/.env \
              --restart unless-stopped \
              --name ${{ env.APP_NAME }} ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.DOCKER_HUB  }}:main_v${{ steps.version.outputs.current-version }}_sha-${{ steps.git.outputs.short_sha }}
          host: ${{ secrets.SSH_HOST }}
          port: ${{ secrets.SSH_PORT }}
          user: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}

      - name: Clean
        uses: fifsky/ssh-action@master
        continue-on-error: true
        with:
          command: |
            docker container prune --force
            docker image prune --force
            docker rmi $(docker images **/${{ env.DOCKER_HUB }} -q) --force
          host: ${{ env.SSH_HOST }}
          port: ${{ env.SSH_PORT }}
          user: ${{ env.SSH_USER }}
          key: ${{ env.SSH_PRIVATE_KEY }}

  deploy_staging:
    needs: [ build_image ]
    runs-on: ubuntu-latest
    if: ${{ github.ref_name == 'staging' }}
    environment: staging

    env: 
      DOCKER_HUB: ${{ secrets.DOCKER_HUB }}
      APP_NAME: ${{ vars.APP_NAME_STAGING }}
      APP_PORT: 3000
      APP_PORT_EXPOSE: ${{ secrets.APP_PORT_STAGING }}
      APP_NETWORK: app-network

      SSH_HOST: ${{ secrets.SSH_HOST_STAGING }}
      SSH_PORT: ${{ secrets.SSH_PORT_STAGING }}
      SSH_USER: ${{ secrets.SSH_USER_STAGING }}
      SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY_STAGING }}

    steps:
      - name: Git checkout
        uses: actions/checkout@v3
        
      - name: Get short sha commit
        id: git
        run: |
          echo "short_sha=$(git rev-parse --short $GITHUB_SHA)" >> "$GITHUB_OUTPUT"
      
      - name: Get latest version
        id: version
        uses: martinbeentjes/npm-get-version-action@main

      - name: Git
        run: |
          echo Short sha: ${{ steps.git.outputs.short_sha }}
          echo Version is: ${{ steps.version.outputs.current-version }}

      - name: Environment
        run: |
          echo DOCKER_HUB is: ${{ env.DOCKER_HUB }}
          echo APP_NAME is: ${{ env.APP_NAME }}
          echo APP_PORT is: ${{ env.APP_PORT }}
          echo APP_PORT_EXPOSE is: ${{ env.APP_PORT_EXPOSE }}
          echo APP_NETWORK is: ${{ env.APP_NETWORK }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Deploy
        uses: fifsky/ssh-action@master
        with:
          command: |
            docker pull ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.DOCKER_HUB }}:staging_v${{ steps.version.outputs.current-version }}_sha-${{ steps.git.outputs.short_sha }}
            docker stop ${{ env.APP_NAME }} && docker rm ${{ env.APP_NAME }}
            docker network create ${{ env.APP_NETWORK }} --driver=bridge
            docker run -itd \
              --env NODE_ENV=staging \
              --hostname ${{ env.APP_NAME }} \
              --publish ${{ env.APP_PORT_EXPOSE }}:${{ env.APP_PORT }} \
              --network ${{ env.APP_NETWORK }} \
              --volume /app/${{ env.APP_NAME }}/logs/:/app/logs/ \
              --volume /app/${{ env.APP_NAME }}/.env:/app/.env \
              --restart unless-stopped \
              --name ${{ env.APP_NAME }} ${{ secrets.DOCKERHUB_USERNAME }}/${{ env.DOCKER_HUB  }}:staging_v${{ steps.version.outputs.current-version }}_sha-${{ steps.git.outputs.short_sha }}
          host: ${{ env.SSH_HOST }}
          port: ${{ env.SSH_PORT }}
          user: ${{ env.SSH_USER }}
          key: ${{ env.SSH_PRIVATE_KEY }}

      - name: Clean
        uses: fifsky/ssh-action@master
        continue-on-error: true
        with:
          command: |
            docker container prune --force
            docker image prune --force
            docker rmi $(docker images **/${{ env.DOCKER_HUB }} -q) --force
          host: ${{ env.SSH_HOST }}
          port: ${{ env.SSH_PORT }}
          user: ${{ env.SSH_USER }}
          key: ${{ env.SSH_PRIVATE_KEY }}
